package org.jiuling.minio.operation;

import io.minio.*;
import io.minio.errors.*;
import io.minio.http.Method;
import io.minio.messages.Item;
import org.jiuling.local.tools.enums.FileTypeEnum;
import org.jiuling.local.tools.random.UUID;
import org.jiuling.minio.coupler.MinioCoupler;
import org.jiuling.minio.exception.MinioRuntimeException;
import org.jiuling.minio.model.MinioObjectModel;

import java.io.IOException;
import java.io.InputStream;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.ArrayList;
import java.util.List;
import java.util.concurrent.TimeUnit;

/**
 * Minio对象操作
 * @author 紫灵
 * @date 2024年01月08日 20时00分29秒
 */
public class MinioObjectOperation {

    /** Minio客户端 */
    private final MinioClient minioClient;

    public MinioObjectOperation(MinioCoupler minioCoupler) {
        this.minioClient = minioCoupler.minioClient();
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param objectKey 文件key
     * @param filePath 文件路径
     * @param fileType 文件类型
     */
    public void uploadObject(String bucket,String objectKey, String filePath, FileTypeEnum fileType){
        try {
            minioClient.uploadObject(
                    UploadObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectKey)
                            .filename(filePath)
                            .contentType(fileType.getName())
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new MinioRuntimeException(e);
        }
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param filePath 文件路径
     * @param fileType 文件类型
     * @return 文件key
     */
    public String uploadObject(String bucket, String filePath, FileTypeEnum fileType){
        String objectKey = UUID.getUUIDIsWithoutLine();
        this.uploadObject(bucket,objectKey,filePath,fileType);
        return objectKey;
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param objectKey 文件key
     * @param inputStream 输入流
     * @param fileType 文件类型
     */
    public void uploadObject(String bucket, String objectKey, InputStream inputStream, FileTypeEnum fileType){
        uploadObject(bucket,objectKey,inputStream,fileType.getName());
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param objectKey 文件key
     * @param inputStream 输入流
     * @param fileType 文件类型
     */
    public void uploadObject(String bucket, String objectKey, InputStream inputStream, String fileType){
        try {
            minioClient.putObject(
                    PutObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectKey)
                            .stream(inputStream, inputStream.available(), -1)
                            .contentType(fileType)
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new MinioRuntimeException(e);
        }
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param inputStream 输入流
     * @param fileType 文件类型
     * @return 文件key
     */
    public String uploadObject(String bucket, InputStream inputStream, FileTypeEnum fileType){
        return uploadObject(bucket,inputStream,fileType.getName());
    }

    /**
     * 上传文件
     * @param bucket 桶
     * @param inputStream 输入流
     * @param fileType 文件类型
     * @return 文件key
     */
    public String uploadObject(String bucket, InputStream inputStream, String fileType){
        String objectKey = UUID.getUUIDIsWithoutLine();
        this.uploadObject(bucket,objectKey,inputStream,fileType);
        return objectKey;
    }

    /**
     * 获取文件列表
     * @param bucket 桶
     * @return 文件列表
     */
    public List<MinioObjectModel> getObjectList(String bucket)  {
        Iterable<Result<Item>> results = minioClient.listObjects(
                ListObjectsArgs.builder()
                        .bucket(bucket)
                        .recursive(true)
                        .build()
        );

        List<MinioObjectModel> infos = new ArrayList<>();
        results.forEach(result->{
            try {
                MinioObjectModel minioObjectModel = new MinioObjectModel();
                Item item = result.get();
                minioObjectModel.setEtag(item.etag());
                minioObjectModel.setObjectName(item.objectName());
                minioObjectModel.setLastModified(item.lastModified());
                minioObjectModel.setSize(item.size());
                minioObjectModel.setStorageClass(item.storageClass());
                minioObjectModel.setLatest(item.isLatest());
                minioObjectModel.setDirectory(item.isDeleteMarker());
                infos.add(minioObjectModel);
            } catch (ServerException | InsufficientDataException | ErrorResponseException | IOException |
                     NoSuchAlgorithmException | InvalidKeyException | InvalidResponseException | XmlParserException |
                     InternalException e) {
                throw new MinioRuntimeException(e);
            }
        });
        return infos;
    }

    /**
     * 获取临时对象访问地址
     * @param bucket 桶
     * @param objectKey 对象key
     * @param expiry 有效期
     * @param unit 单位
     * @return
     */
    public String getTemporaryObjectUrl(String bucket, String objectKey, Integer expiry, TimeUnit unit){
        try {
            return minioClient.getPresignedObjectUrl(
                    GetPresignedObjectUrlArgs.builder()
                            .method(Method.GET)
                            .bucket(bucket)
                            .object(objectKey)
                            .expiry(expiry, unit)
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | XmlParserException |
                 ServerException e) {
            throw new MinioRuntimeException(e);
        }
    }

    /**
     * 获取文件数据流
     * @param bucket 桶
     * @param objectKey 文件key
     * @return 数据流
     */
    public InputStream getObjectInputStream(String bucket, String objectKey){
        try {
            return minioClient.getObject(
                    GetObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectKey)
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new MinioRuntimeException(e);
        }
    }

    /**
     * 对象复制
     * @param sourceBucket    源桶
     * @param sourceObjectKey 源文件key
     * @param bucket          桶
     * @param objectKey       文件key
     */
    public void copyObject(String sourceBucket,String sourceObjectKey,String bucket,String objectKey){
        try {
            minioClient.copyObject(
                    CopyObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectKey)
                            .source(CopySource.builder()
                                    .bucket(sourceBucket)
                                    .object(sourceObjectKey)
                                    .build())
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new MinioRuntimeException(e);
        }
    }

    /**
     * 对象复制
     * @param sourceBucket    源桶
     * @param sourceObjectKey 源文件key
     * @param bucket          桶
     * @return 文件key
     */
    public String copyObject(String sourceBucket,String sourceObjectKey,String bucket){
        String objectKey = UUID.getUUIDIsWithoutLine();
        this.copyObject(sourceBucket, sourceObjectKey, bucket,objectKey);
        return objectKey;
    }

    /**
     * 删除对象
     * @param bucket 桶
     * @param objectKey 对象key
     */
    public void deleteObject(String bucket, String objectKey){
        try {
            minioClient.removeObject(
                    RemoveObjectArgs.builder()
                            .bucket(bucket)
                            .object(objectKey)
                            .build()
            );
        } catch (ErrorResponseException | InsufficientDataException | InternalException | InvalidKeyException |
                 InvalidResponseException | IOException | NoSuchAlgorithmException | ServerException |
                 XmlParserException e) {
            throw new MinioRuntimeException(e);
        }
    }
}
